#ifndef A8_STRUTILS
#define A8_STRUTILS

#include <string.h>
#include <string>
#include <vector>
#include <assert.h>
#include <a8/xvalue.hpp>

#ifdef _MSC_VER 	
#define strncasecmp		_strnicmp	 
#define strcasecmp		_strcmpi
#endif

typedef std::map<std::string, std::string > HTTP_QUERY;

namespace a8
{
	static std::string bin2hex(const std::string& binstr)
	{
		std::string result;
		for(int i = 0; i < binstr.size(); i++){
			
		}
		return result;
	}

	static const char* getvalidstr1(const char* szLine, char **pp, int& iLen, const char* szIngore)
	{
		//skip ingorechars
		*pp = (char*)szLine;
		while(*pp && **pp && strchr(szIngore, **pp)) (*pp)++;
		//read validchars
		iLen = 0;
		while((*pp + iLen) && *(*pp + iLen) && !strchr(szIngore, *(*pp + iLen++))) ;
		if (!strchr(szIngore, *(*pp + iLen))){
			iLen--;  
		}		
		return *pp + iLen ;
	}

	static std::string getvalidstr(const std::string& strLine, std::string& strVal, const char* szIngore = " \t")
	{
		char *pp = NULL;
		int iLen = 0;
		const char *result = a8::getvalidstr1(strLine.c_str(), &pp, iLen, szIngore);
		strVal.assign(pp, iLen);
		return result ? std::string(result) : "";
	}

	static std::string trim(const std::string& str)
	{
		std::string text = str;
		if(!text.empty()){  
			text.erase(0, text.find_first_not_of(" \n\r\t"));  
			text.erase(text.find_last_not_of(" \n\r\t") + 1);  
		}  
		return text;
	}

	//only %d %f %s
	static std::string format(const char* fmt, const std::vector<a8::XValue>& args)
	{
		std::string result;
		result.reserve(1024);
		int curarg = 0;
		const char *p = fmt;
		while(*p){
			if(*p == '%' && *(p+1)){
				p++;
				switch(*p){
				case 'd':
					result.append(args[curarg++].GetString().c_str());
					break;
				case 'f':
					result.append(args[curarg++].GetString().c_str());
					break;
				case 's':
					result.append(args[curarg++].GetString().c_str());
					break;
				default:{
					result.push_back('%');
					result.push_back(*p);
				}
				}
			}else{
				result.push_back(*p);
			}
			p++;
		}
		return result;
	}

	static std::string format(const char* fmt, a8::XValue* args, int argnum)
	{
		std::string result;
		result.reserve(1024);
		int curarg = 0;
		const char *p = fmt;
		while(*p){
			if(*p == '%' && *(p+1)){
				p++;
				switch(*p){
				case 'd':
					result.append(args[curarg++].GetString().c_str());
					break;
				case 'f':
					result.append(args[curarg++].GetString().c_str());
					break;
				case 's':
					result.append(args[curarg++].GetString().c_str());
					break;
				default:{
					result.push_back('%');
					result.push_back(*p);
				}
				}
			}else{
				result.push_back(*p);
			}
			p++;
		}
		return result;
	}

	static std::string format(const char* fmt, a8::XValue arg)
	{
		return format(fmt, &arg, 1);
	}

	static std::string format(const char* fmt, a8::XValue arg1, a8::XValue arg2)
	{
		std::vector<a8::XValue> params;
		params.push_back(arg1);
		params.push_back(arg2);
		return format(fmt, params);
	}

	template<typename T1>
	static std::string format(const char* fmt, const T1& t1)
	{
		a8::XValue args[] = {t1};
		return a8::format(fmt, args, 1);
	}

	template<
		typename T1,
		typename T2
	>
	static std::string format(const char* fmt, const T1& t1, const T2& t2)
	{
		a8::XValue args[] = {t1, t2};
		return a8::format(fmt, args, 2);
	}

	template<
		typename T1,
		typename T2,
		typename T3
	>
	static std::string format(const char* fmt, const T1& t1, const T2& t2, const T3& t3)
	{
		a8::XValue args[] = {t1, t2, t3};
		return a8::format(fmt, args, 3);
	}

	template<
		typename T1,
		typename T2,
		typename T3,
		typename T4
	>
	static std::string format(const char* fmt, const T1& t1, const T2& t2, const T3& t3, const T4& t4)
	{
		a8::XValue args[] = {t1, t2, t3, t4};
		return a8::format(fmt, args, 4);
	}

	static void split(const std::string& str, std::vector<std::string>& list, char separator=',')
	{
		const char *p  = str.c_str();
		const char *pv = p;
		while(*p){
			if(*p == separator){
				if(p > pv){
					list.push_back(std::string(pv, p - pv));
				}else{
					list.push_back("");
				}
				pv = p + 1;
			}
			p++;
		}
		if(*p  == separator){
			list.push_back("");
		}else if(p > pv){
			list.push_back(std::string(pv, p - pv));
		}
	}

	inline static unsigned char fromhex(unsigned char x)
    {
        return isdigit(x) ? x-'0' : x-'A'+10;
    }

	static unsigned char ToHex(unsigned char x)   
	{   
		return  x > 9 ? x + 55 : x + 48;   
	} 

	static std::string urlencode(const std::string& str)  
	{  
		std::string strTemp = "";  
		size_t length = str.length();  
		for (size_t i = 0; i < length; i++)  
			{  
				if (isalnum((unsigned char)str[i]) ||   
					(str[i] == '-') ||  
					(str[i] == '_') ||   
					(str[i] == '.') ||   
					(str[i] == '~'))  
					strTemp += str[i];  
				else if (str[i] == ' ')  
					strTemp += "+";  
				else  
					{  
						strTemp += '%';  
						strTemp += ToHex((unsigned char)str[i] >> 4);  
						strTemp += ToHex((unsigned char)str[i] % 16);  
					}  
			}  
		return strTemp;  
	}  

	inline static std::string urldecode(const std::string &sIn)
    {
		std::string sOut;
        for(unsigned int i = 0; i < sIn.size(); i++ ){
			unsigned char ch = 0;
			if(sIn[i] == '%'){
				ch = (fromhex(sIn[i + 1]) << 4);
				ch |= fromhex(sIn[i + 2]);
				i += 2;
			}else if(sIn[i] == '+'){
				ch = ' ';
			}
			else{
				ch = sIn[i];
			}
			sOut += (char)ch;
		}
        return sOut;
    }

	static void parser_urlquerystring(const char* querystring, HTTP_QUERY& query)
	{
		if(!querystring || *querystring == 0){
			return;
		}
		std::vector<std::string> params;
		split(std::string(querystring), params, '&');
		for(unsigned int i = 0; i < params.size(); i++){
			int pos = params[i].find('=');
			if(pos > 0){
				std::string key = params[i].substr(0, pos);
				std::string val = params[i].substr(pos + 1, params[i].size() - pos);
				val = urldecode(val);
				query[key] = val;
			}
		}
	}

	static void parser_urlquerystring(const char* querystring, int len, HTTP_QUERY& query)
	{
		if(len == 0){
			return;
		}
		std::string tmpstr;
		tmpstr.append(querystring, len);
		parser_urlquerystring(tmpstr.c_str(), query);
	}

	static a8::XValue REQUEST(const HTTP_QUERY& query, const char* name, const char* defval="")
	{
		HTTP_QUERY::const_iterator itr = query.find(name);
		return itr != query.end() ? a8::XValue(itr->second) : a8::XValue(defval);
	}

	static void replace_string(std::string& basestr, const std::string& srcstr, const std::string& deststr)
	{
		std::string::size_type pos = 0;  
		std::string::size_type srcLen = srcstr.size();  
		std::string::size_type desLen = deststr.size();  
		pos = basestr.find(srcstr, pos);   
		while((pos != std::string::npos)){  
			basestr.replace(pos, srcLen, deststr);  
			pos = basestr.find(srcstr, (pos + desLen));  
		}		
	}
}

#endif
